#include "face.h"



//--------------------- Constructeurs et destructeur -------------------
/* ****************************************************************
 * Constructeur par défault
 * **************************************************************** */
Face::Face()
{
    _normale = new Point();
}

/* ****************************************************************
 * Constructeur prenant une liste de sommets
 * @param listeSommets : liste des sommets de la novuelle face
 * **************************************************************** */
Face::Face(QList<Sommet*> listeSommets, Point& normale)
    : _sommets(listeSommets)
{
    *_normale = normale;
}

/* ****************************************************************
 * Constructeur de recopie
 * @param face : face à recopier dans cette nouvelle face
 * **************************************************************** */
Face::Face(const Face& face)
{
    //On recopie chaque sommet de la face dans la nouvelle
    for(int i = 0; i < face._sommets.size(); ++i)
    {
        this->_sommets.push_back(new Sommet((*face._sommets[i])));
    }

    _normale = face._normale;
}

/* ****************************************************************
 * Destructeur de la classe face
 * **************************************************************** */
Face::~Face()
{
    delete _normale;

    for(int i = 0; i < _sommets.size(); ++i)
    {
        delete _sommets[i];
    }
}

//----------------------------------------------------------------------
//--------------------- Méthodes ---------------------------------------

/* ****************************************************************
 * On renvoie le nombre de sommets de la face
 * @return int : le nombre de sommets de la face
 * **************************************************************** */
int Face::getNbSommets()
{
    return _sommets.size();
}

/* ****************************************************************
 * On calcule le centre de gravité de la face,
 * si la face est vide, on renvoie une exception
 * @return Point& : le centre de gravité de face
 * **************************************************************** */
Point& Face::getCentreGravite()
{
    if(_sommets.size() <= 0)
    {
        throw std::string("Face.getCentreGravite : erreur, la face est vide");
    }

    GLfloat x = 0.0;
    GLfloat y = 0.0;
    GLfloat z = 0.0;

    for(int i = 0; i < _sommets.size(); ++i)
    {
        x += _sommets[i]->getX();
        y += _sommets[i]->getX();
        z += _sommets[i]->getX();
    }

    x /= (GLfloat) _sommets.size();
    y /= (GLfloat) _sommets.size();
    z /= (GLfloat) _sommets.size();

    Point* retour = new Point(x, y, z);
    return (*retour);
}

/* ****************************************************************
 * On renvoie la normale de la face
 * @return Vecteur& : le vecteur de la normale de la face
 * **************************************************************** */
Point& Face::getNormale()
{
    return *_normale;
}

/* ****************************************************************
 * Fonction permettant d'ajouter un nouveau sommet à la face
 * @param s : sommet à rajouter
 * **************************************************************** */
void Face::ajouterSommet(Sommet& s)
{
    _sommets.push_back(&s);
}

/* ****************************************************************
 * Permet de calculer la normale normée de la face
 * **************************************************************** */
void Face::calculerNormale()
{
    if(this->_sommets.size() >= 3)
    {
        GLfloat nx, ny, nz;

        GLfloat V12_x = _sommets[1]->getX() - _sommets[0]->getX();
        GLfloat V13_x = _sommets[2]->getX() - _sommets[0]->getX();
        GLfloat V12_y = _sommets[1]->getY() - _sommets[0]->getY();
        GLfloat V13_y = _sommets[2]->getY() - _sommets[0]->getY();
        GLfloat V12_z = _sommets[1]->getZ() - _sommets[0]->getZ();
        GLfloat V13_z = _sommets[2]->getZ() - _sommets[0]->getZ();

        nx = V12_y * V13_z - V12_z * V13_y;
        ny = V12_z * V13_x - V12_x * V13_z;
        nz = V12_x * V13_y - V12_y * V13_x;

        GLfloat longueur = sqrt(nx*nx + ny*ny + nz*nz);

        nx /= longueur;
        ny /= longueur;
        nz /= longueur;

        //TODO : Vérifier infini

        _normale->setX(nx);
        _normale->setY(ny);
        _normale->setZ(nz);
    }
}

/* ****************************************************************
 * Fonction de dessin de la face
 * **************************************************************** */
void Face::dessiner()
{
    utiliserNormale();

    glBegin(GL_POLYGON);
        for(int i = 0; i < _sommets.size(); ++i)
        {
            glTexCoord2f(_sommets[i]->getU(), _sommets[i]->getV());
            glVertex3f(_sommets[i]->getX(), _sommets[i]->getY(), _sommets[i]->getZ());
        }
    glEnd();
}

/* ****************************************************************
 * On utilise la normale de la face avant de la dessiner
 * **************************************************************** */
void Face::utiliserNormale()
{
    glNormal3f(_normale->getX(), _normale->getY(), _normale->getZ());
}

//----------------------------------------------------------------------
//--------------------- Accesseurs -------------------------------------

/* ****************************************************************
 * Accesseur permettant de récupérer le sommet i de la face.
 * On renvoie une exception si i n'est pas correct.
 * @param i : indice du sommet à récupérer
 * **************************************************************** */
Sommet& Face::getSommet(int i)
{
    if(i < 0 || i > _sommets.size())
    {
        throw std::string("Face.getSommet : erreur, l'indice i est hors limite.");
    }

    return (*_sommets[i]);
}

//----------------------------------------------------------------------
//--------------------- Surcharge des opérateurs -----------------------

//----------------------------------------------------------------------
